<?php
/*观察者模式

“观察者模式”的关系：在活动季，底部的“开始预订按钮”会变成“秒杀按钮”（所谓秒杀按钮，就是一个显示成灰色不可点击，并且一直处于倒计时状态的按钮，直到到达秒杀时间，比如0点整，秒杀按钮才由灰色变为橘黄色，并且可以点击）, 当秒杀时间到时，不光底部的“秒杀按钮”变为“开始预订按钮”，可选班期的几个按钮也从灰色不可点击状态，变为白色可点击状态。相信熟悉设计模式的人已经想到这就是“观察者模式”。
https://blog.csdn.net/colinandroid/article/details/81113013

* 当对象间存在一对多关系时，则使用观察者模式（Observer Pattern）。
* 比如，当一个对象被修改时，则会自动通知它的依赖对象。观察者模式属于行为型模式。
* 一个对象 目标对象 的状态发生改变，所有的依赖对象（观察者对象）都将得到通知，进行广播通知。*/


//************ 一个改变， 多个改变
?><?php
//Subject.class.php 目标类
namespace Observer;

class Subject
{
    private $state;

    private $observers = [];

    public function getState()
    {
        return $this->state;
    }

    public function seState($state)
    {
        $this->state = $state;
        $this->notifyAllObjects();
    }

    public function register(Observer $object)
    {
        $this->observers[] = $object;
    }

    public function remove($object)
    {
        foreach ($this->observers as $key => $observer) {
            if ($observer == $object){
                unset($this->observers[$key]);
            }
        }
    }

    public function notifyAllObjects()
    {
        foreach ($this->observers as $observer) {
            $observer->update();
        }
    }
}
?>
<?php
//Observer.class.php（观察者抽象父类）
namespace Observer;

abstract class Observer
{
    protected $subject;

    public abstract function update();
}
?>

<?php
//ObjectA.class.php （具体抽象类A）
namespace Observer;

class ObserverA extends Observer
{
    private $myState = 'init A';

    public function __construct(Subject $subject)
    {
        $this->subject = $subject;
        $this->subject->register($this);
    }

    public function update()
    {
        $this->myState = $this->subject->getState();
    }

    public function getSate()
    {
        return "ObserverA get state:".$this->myState;
    }
}
?>

<?php
//ObserverB.class.php（具体观察者B）
namespace Observer;

class ObserverB extends Observer
{
    private $myState = 'init B';

    public function __construct(Subject $subject)
    {
        $this->subject = $subject;
        $this->subject->register($this);
    }

    public function update()
    {
        $this->myState = $this->subject->getState();
    }

    public function getSate()
    {
        return "ObserverB get state:".$this->myState;
    }
}
?>


<?php
//用法
//observer.php
spl_autoload_register(function ($className){
    $className = str_replace('\\','/',$className);
    include $className.".class.php";
});


/*
ObserverA get state:init A
ObserverB get state:init B
ObserverA get state:hello
ObserverB get state:hello
*/
$subject = new Subject();
$objectA = new ObserverA($subject); $objectB = new ObserverB($subject); echo $objectA->getSate(); echo '<br/>'; echo $objectB->getSate();
echo '<br/>';
$subject->seState("hello");
echo $objectA->getSate(); echo '<br/>'; echo $objectB->getSate(); echo '<br/>';
?>
